package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.crypto.KeySelector;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author huanghui
 * @since 2023-07-20
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final LearningRecordMapper recordMapper;


    @Override
    @Transactional
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //1.查看课程有效期
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(courseIds);
        //2.判断课程信息是否为空
        if (CollUtils.isEmpty(cInfoList)){
            log.error("课程信息不存在无法添加到课表");
            return;
        }
        //3循环遍历，处理learningLessons数据
        List<LearningLesson> lessonList = new ArrayList<>(cInfoList.size());
        for (CourseSimpleInfoDTO courseInfo : cInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            //3.1 获取过期时间
            Integer validDuration = courseInfo.getValidDuration();
            if (validDuration!=null && validDuration>0){
                LocalDateTime now = LocalDateTime.now();
                learningLesson.setExpireTime(now.plusMonths(validDuration));
                learningLesson.setCreateTime(now);
            }

            //3.1 填充 courseId ,userId
            learningLesson.setCourseId(courseInfo.getId());
            learningLesson.setUserId(userId);
            lessonList.add(learningLesson);
        }
        //4.批量处理
        saveBatch(lessonList);
    }

    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
        //1.查询当前用户Id
        Long userId = UserContext.getUser();
        //2.分页查询
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }


        Map<Long, CourseSimpleInfoDTO> cmap = queryCourseSimpleInfoList(records);

        //4.封装LearningLessonVO
        List<LearningLessonVO> list = new ArrayList<>(records.size());

        //4.1 循环遍历，LearningLesson转变为LearningLessonVO
        for (LearningLesson record : records) {
            //基础属性拷贝
            LearningLessonVO vo = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO cInfo = cmap.get(record.getCourseId());
            vo.setCourseId(cInfo.getId());
            vo.setCourseName(cInfo.getName());
            vo.setCourseCoverUrl(cInfo.getCoverUrl());
            vo.setSections(cInfo.getSectionNum());
            list.add(vo);

        }
        return PageDTO.of(page, list);
        //return new PageDTO<>(page.getTotal(),page.getSize(),list);
    }




    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        //1.查询当前用户Id
        Long userId = UserContext.getUser();
        // 2.查询正在学习的课程  select * from xx where user_id = #{userId} AND status = 1 order by latest_learn_time limit 1
        //    LearningLesson lesson = lambdaQuery()
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        // 3.拷贝PO基础属性到VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        // 4.查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        //4.1 健壮性判断
        if(cInfo==null){
            throw new BadRequestException("课程不存在");
        }
        //4.2 补充属性值
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());
        // 5.统计课表中的课程数量
        Integer courseAmount = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        vo.setCourseAmount(courseAmount);
        // 6.查询小节信息
        List<CataSimpleInfoDTO> cataInfos = catalogueClient
                .batchQueryCatalogue(CollUtils
                        .singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)){
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionIndex(cataInfo.getCIndex());
            vo.setLatestSectionName(cataInfo.getName());
        }
        return vo;
    }

    @Override
    public LearningLessonVO queryMyLessonStatusById(Long courseId) {
        //1.查询当前用户Id
        Long userId = UserContext.getUser();
        //2.根据id,courseId,
        //2.1 生成查询条件
        LearningLesson lesson = this.getOne(buildUserIdAndCourseIdWrapper(userId,courseId));
        //2.2健壮性判断
        if(lesson==null){
            throw  new BadRequestException("查询不到课程");
        }
        //3 属性拷贝 Po 转变为Vo
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        return vo;
    }

    @Override
    public void deleteMyLessonByCourseId(Object object,Long courseId) {
        //1.查询当前用户Id
        Long userId = UserContext.getUser();
        //2.执行删除课程操作
        this.remove(buildUserIdAndCourseIdWrapper(userId,courseId));
    }

    /** @author ZXX-挚爱
    * @Description 检查课程是否有效
    * @Dete 17:17 2023/7/21
    * @Param [courseId]
    * @return java.lang.Long
    **/
    
    @Override
    public Long isLessonValid(Long courseId) {
        //1.获取当前用户id
        Long userId = UserContext.getUser();
        LearningLesson lesson = this.getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        //2.判断课程是否失效
        if(lesson==null || lesson.getStatus().equals(LessonStatus.EXPIRED)){
            return null;
        }
        return lesson.getId();
    }

    /** @author ZXX-挚爱
    * @Description 统计课程的学习人数
    * @Dete 19:20 2023/7/21
    * @Param [courseId]
    * @return java.lang.Integer
    **/

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //1.生成查询条件
        Integer count = lambdaQuery().eq(LearningLesson::getCourseId, courseId).in(LearningLesson::getStatus,
                LessonStatus.NOT_BEGIN.getValue(),
                LessonStatus.LEARNING.getValue(),
                LessonStatus.FINISHED.getValue()).count();
        return count;
    }

    @Override
    public LearningLesson queryByUserIdAndCourseId(Long userId, Long courseId) {
        return getOne(buildUserIdAndCourseIdWrapper(userId, courseId));

    }

    @Override
    public void createLearningPlans(Long courseId, Integer freq) {
        //1.获取当前用户登录的id
        Long userId = UserContext.getUser();
        //2.查询课表中的指定课程有关的数据
        LearningLesson lesson = queryByUserIdAndCourseId(userId, courseId);
        AssertUtils.isNotNull("课程信息不存在");
        //3.修改数据
        LearningLesson l = new LearningLesson();
        l.setId(lesson.getId());
        l.setWeekFreq(freq);
        if (lesson.getPlanStatus()==PlanStatus.NO_PLAN) {
            l.setPlanStatus(PlanStatus.PLAN_RUNNING);
        }
        updateById(l);
    }

    /** @author ZXX-挚爱
    * @Description 查询学习计划
    * @Dete 17:34 2023/7/24
    * @Param [query]
    * @return com.tianji.learning.domain.vo.LearningPlanPageVO
    **/

    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery query) {
        LearningPlanPageVO result = new LearningPlanPageVO();
        //1.获取当前登录用户
        Long userId = UserContext.getUser();
        //2.获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        //3.查询总的的统计数据
        //3.1.本周总的已学习小节数据
        LambdaQueryWrapper<LearningRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(LearningRecord::getUserId,userId)
                .eq(LearningRecord::getFinished,true)
                        .gt(LearningRecord::getFinishTime,begin)
                        .lt(LearningRecord::getFinishTime,end);
        Integer weekFinished = recordMapper.selectCount(lqw);
        result.setWeekFinished(weekFinished);
        //3.2.本周总的计划学习小节数据
         Integer weekTotalPlan=getBaseMapper().queryTotalPlan(userId);
         result.setWeekTotalPlan(weekTotalPlan);
        //TODO 3.3.本周学习积分
        //4.查询分页数据
        //4.1.分页查询课表信息以及学习计划信息
        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return result.emptyPage(page);
        }

        //4.2.查询课表对应的课程信息
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
        //4.3.统计每一个课程本周已经学习的小节数量
        List<IdAndNumDTO> list=  recordMapper.countLearnedSections(userId,begin,end);
        Map<Long, Integer> countMap = IdAndNumDTO.toMap(list);
        //4.4.组装数据VO
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson r : records) {
            //4.4.1 拷贝基础属性
            LearningPlanVO vo = BeanUtils.copyBean(r, LearningPlanVO.class);
            //4.4.2 填充课程详细信息
            CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
            if (cInfo != null) {
                vo.setCourseName(cInfo.getName());
                vo.setSections(cInfo.getSectionNum());
            }
            //4.4.3.每个课程的本周已经学习的小节数量
            vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0));
            voList.add(vo);
        }
        return result.pageInfo(page.getTotal(),page.getPages(),voList);
    }

    public Wrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> lqw = new LambdaQueryWrapper<>();
        lqw.eq(LearningLesson::getUserId,userId).eq(LearningLesson::getCourseId,courseId);
        return lqw;
    }
    private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
        //3.查询课程信息
        //3.1课程集合转换为map
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if (CollUtils.isEmpty(cInfoList)){
            throw new BadRequestException("课程信息不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cmap = cInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        return cmap;
    }
}
